using System;
using System.Collections.Generic;

namespace PropSys
{
    public class PropFloat
    {
        private float _baseVal;
        private float _addVal;
        private float _pctVal;
        private float _adtVal;
        /// <summary>
        /// Buff reg.
        /// </summary>
        private Dictionary<string, Func<float>> _add;
        /// <summary>
        /// Buff reg.
        /// </summary>
        private Dictionary<string, Func<float>> _pct;
        /// <summary>
        /// Buff reg.
        /// </summary>
        private Dictionary<string, Func<float>> _adt;
        private Action ON_UpdAdd;
        private Action ON_UpdPct;
        private Action ON_UpdAdt;
        public float Val { get => (_baseVal + _addVal) * _pctVal + _adtVal; }
        public float ModifiedVal { get => (_baseVal + _addVal) * _pctVal; }

        public PropFloat()
        {
            _add = new Dictionary<string, Func<float>>();
            _pct = new Dictionary<string, Func<float>>();
            _adt = new Dictionary<string, Func<float>>();
            ON_UpdAdd = delegate { };
            ON_UpdPct = delegate { };
            ON_UpdAdt = delegate { };
            _addVal = 0;
            _pctVal = 1;
            _adtVal = 0;
        }

        public PropFloat(float baseVal) : this()
        {
            _baseVal = baseVal;
        }

        public void SetBaseVal(float baseVal)
        {
            _baseVal = baseVal;
        }

        private void UpdAdd()
        {
            _addVal = 0f;
            foreach (Func<float> func in _add.Values) _addVal += func();
            ON_UpdAdd();
        }

        private void UpdPct()
        {
            _pctVal = 1f;
            foreach (Func<float> func in _pct.Values) _pctVal *= 1f + func() / 100f;
            ON_UpdPct();
        }

        private void UpdAdt()
        {
            _adtVal = 0f;
            foreach (Func<float> func in _adt.Values) _adtVal += func();
            ON_UpdAdt();
        }

        public void RegVal(PropReg pr, string key, Func<float> val)
        {
            switch (pr)
            {
                case PropReg.ADD:
                    if (_add.ContainsKey(key)) _add[key] = val;
                    else _add.Add(key, val);
                    UpdAdd();
                    break;
                case PropReg.PCT:
                    if (_pct.ContainsKey(key)) _pct[key] = val;
                    else _pct.Add(key, val);
                    UpdPct();
                    break;
                case PropReg.ADT:
                    if (_adt.ContainsKey(key)) _adt[key] = val;
                    else _adt.Add(key, val);
                    UpdAdt();
                    break;
                default:
                    break;
            }
        }

        public void UregVal(PropReg pr, string key)
        {
            switch (pr)
            {
                case PropReg.ADD:
                    if (_add.ContainsKey(key)) _add.Remove(key);
                    UpdAdd();
                    break;
                case PropReg.PCT:
                    if (_pct.ContainsKey(key)) _pct.Remove(key);
                    UpdPct();
                    break;
                case PropReg.ADT:
                    if (_adt.ContainsKey(key)) _adt.Remove(key);
                    UpdAdt();
                    break;
                default:
                    break;
            }
        }

        public void RegUpdEvt(PropReg PR, Action action)
        {
            switch (PR)
            {
                case PropReg.ADD:
                    ON_UpdAdd += action;
                    break;
                case PropReg.PCT:
                    ON_UpdPct += action;
                    break;
                case PropReg.ADT:
                    ON_UpdAdt += action;
                    break;
                default:
                    break;
            }
        }

        public void UregUpdEvt(PropReg PR, Action action)
        {
            switch (PR)
            {
                case PropReg.ADD:
                    ON_UpdAdd -= action;
                    break;
                case PropReg.PCT:
                    ON_UpdPct -= action;
                    break;
                case PropReg.ADT:
                    ON_UpdAdt -= action;
                    break;
                default:
                    break;
            }
        }
    }
}
